
//
// Copyright 2009 Arne Halvorsen (arne.halvorsen@gmail.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Project page: http://code.google.com/p/mf4j/

//
// 091116 - aha42 - Starts in line change tracking.
// 091121 - aha42 - Added project page link (google code) to header comment.
// 091210 - aha42 - IOException -> FlickrException.
//

package org.aha.mf4j;

import java.io.CharArrayWriter;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.aha.mf4j.reflection.FlickrArgument;
import org.aha.mf4j.reflection.FlickrError;
import org.aha.mf4j.reflection.FlickrMethod;
import org.aha.mf4j.reflection.Reflection;
import org.aha.mf4j.response.FlickrObject;

/**
 * <p>
 *   {@link Reflection} implementations.
 * </p>
 * @author Arne Halvorsen (aha42).
 */
final class ReflectionImpl implements Reflection 
{ 
  private final Set<String> m_metNames=new HashSet<String>();
  
  private final Map<String, FlickrMethod> m_methods=
    new TreeMap<String, FlickrMethod>();
  
  private final FlickrSession m_session;
  
  /**
   * <p>
   *   Constructor.
   * </p>
   * @param fs Session.
   */
  ReflectionImpl(FlickrSession fs) throws FlickrException
  {
    if (fs==null)
    {
      throw new NullPointerException("fs");
    }
    
    m_session=fs;
    
    String apiKey=fs.getApiKey();
    
    Request req=new Request();
    
    req.setApiKey(apiKey).setMethod("flickr.reflection.getMethods");
    
    FlickrObject resFo=req.perform();
    
    FlickrObject methodsFo=resFo.getMandatoryChild("methods");
    
    FlickrObject[] methodFos=methodsFo.getChildren("method");
    
    int n=methodFos.length;
    for (int i=0; i<n; i++) m_metNames.add(methodFos[i].getValue());
  }
  
  // Specified in Reflection.
  public boolean methodExists(String name){ return m_metNames.contains(name); } 
  
  // Specified in Reflection.
  public FlickrMethod getMethod(String name) throws FlickrException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    
    if (!m_metNames.contains(name))
    {
      throw new IllegalArgumentException("not a method : "+name);
    }
    
    FlickrMethod retVal=m_methods.get(name);
    if (retVal==null)
    {
      Request req=new Request();
        
      req.setApiKey(m_session.getApiKey())
         .setMethod("flickr.reflection.getMethodInfo");
      
      req.setArg("method_name", name);
      
      retVal=new FlickrMethod(req.perform());
      m_methods.put(name, retVal);
    }
    return retVal;
  }
  
  @Override
  public String toString() 
  {
    CharArrayWriter caw=new CharArrayWriter();
    PrintWriter pw=new PrintWriter(caw);
    
    pw.println("Methods: ");
    
    Iterator<FlickrMethod> methods=m_methods.values().iterator();
    while (methods.hasNext())
    {
      FlickrMethod curr=methods.next();
      
      pw.println();
      pw.println("  name : "+curr.getName());
      
      String desc=curr.getDescription();
      if (desc!=null) pw.println("  description : "+desc);
      
      String exp=curr.getExplanation();
      if (exp!=null) pw.println("  explanation : "+exp);
      
      String resp=curr.getResponse();
      if (resp!=null) pw.println("  response : "+resp);
      
      FlickrArgument[] args=curr.getArguments();
      int n=args.length;
      if (n>0)
      {
        pw.println("    Arguments:");
        for (int i=0; i<n; i++)
        {
          FlickrArgument arg=args[i];
          pw.println("      "+arg);
        }
      }
      
      n=curr.getErrorCount();
      if (n>0)
      {
        pw.println("    Errors:");
        for (int i=0; i<n; i++)
        {
          FlickrError err=curr.getError(i);
          pw.println("      "+err.getErrorCode()+" : "+err.getMessage());
        }
      }
    }
    
    pw.flush();
    return caw.toString();
  }
  
}
